
尽管C++的概念已经研究了很多年，并且实验性的实现已经出现了十多年，但广泛的使用才刚刚开始。我们希望本书的未来版本能够提供关于如何设计受约束模板库的实用指南，我们先给出了三个观察结果。

\subsubsubsection{E.4.1\hspace{0.2cm}测试概念}

概念是布尔谓词，有效的常量表达式。给定一个概念C和一些类型T1, T2，…模型的概念，可以静态地断言观察:

\begin{lstlisting}[style=styleCXX]
static_assert(C<T1, T2, ...>, "Model failure");
\end{lstlisting}

设计概念时，建议也设计以这种方式测试其简单类型。包括挑战概念界限的类型，则需要回答如下问题:

\begin{itemize}
\item 
接口和/或算法需要复制和/或移动建模类型的对象吗?

\item 
哪些转换是可以接受的?需要哪些转换?

\item 
模板假定的基本操作集唯一么?例如，可以使用*=或*和=操作吗?
\end{itemize}

这里，了解概念的原型(参见28.3节)也很有用。

\subsubsubsection{E.4.2\hspace{0.2cm}概念的粒度}

随着概念成为C++语言的一部分，就可以对“概念库”进行构建了，就像我们在这些特性可用时构建类库和模板库一样。与其他库一样，我们也很希望以各种方式对概念进行分层。这里，简要地讨论了迭代器类别的例子，假设可以在这些类别之外构建“范围类别”，或者在这些类别之上构建“序列概念”等。

另一方面，会试图在“基本语法”概念的基础上构建所有这些概念。例如:

\begin{lstlisting}[style=styleCXX]
template<typename T, typename U>
concept Addable =
requires (T x, U y) {
	x + y;
}
\end{lstlisting}

不建议这样做，因为这是一个没有明确语义的概念。当T和U都是std::string或者当一个类型是指针而另一个是整型，当然还有算术类型时，概念条件就满足了。在这三种情况下，可添加的概念有一些不同的含义(分别是连接、迭代器位移和算术加法)。因此，引入这样的概念将导致库接口模糊，并可能引起歧义。

相反，概念似乎最适合用于建模问题领域中出现的语义概念。以一种纪律性的方式来做这件事，会改善库的整体设计，因为将给使用者带来一致和明确的接口。当标准模板库(STL)添加到C++标准库中时，情况就是如此。尽管它没有使用基于语言的“概念”，但在设计时在很大程度上考虑了概念的思想(如迭代器和迭代器层次结构)，其余的都已成为历史了。

\subsubsubsection{E.4.3\hspace{0.2cm}二进制兼容性}

资深C++开发者知道，当某些实体(特别是函数和成员函数)会在编译为低层机器码时，相关联的名称会将声明名称与实体类型和作用范围相结合。这个名称，通常称为实体的重组名称，是实际为链接器提供实体的引用(例如，来自其他对象文件)的名称。例如，定义为的函数的重组名称

\begin{lstlisting}[style=styleCXX]
namespace X {
	void f() {}
}
\end{lstlisting}

使用EvItanium C++ ABI [ItaniumABI]时是\_ZN1X1f，其中的字母X和f分别来自命名空间名和函数名。

混乱的名称不能在程序中“冲突”，若两个函数可能在一个程序中共存，那必须具有不同的、混乱的名称。反之，约束必须在函数名中编码(因为模板特化除了约束和函数体之外，其他方面都是相同的，可以出现在不同的翻译单元中)。考虑以下两个翻译单元:

\begin{lstlisting}[style=styleCXX]
#include <iostream>

template<typename T>
concept HasPlus = requires (T x, T y) {
	x+y;
};

template<typename T> int f(T p) requires HasPlus<T> {
	std::cout << "TU1\n";
}

void g();

int main() {
	f(1);
	g();
}
\end{lstlisting}

和

\begin{lstlisting}[style=styleCXX]
#include <iostream>

template<typename T>
concept HasMult = requires (T x, T y) {
	x*y;
};

template<typename T> int f(T p) requires HasMult<T> {
	std::cout << "TU2\n";
}

template int f(int);

void g() {
	f(2);
}
\end{lstlisting}

程序必须输出

\begin{tcblisting}{commandshell={}}
TU1
TU2
\end{tcblisting}

这意味着f()的两个定义必须以不同的方式处理。

\begin{tcolorbox}[colback=webgreen!5!white,colframe=webgreen!75!black]
\hspace*{0.75cm}GCC 7.1中对概念的实验实现在这方面有缺陷。
\end{tcolorbox}























